home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / sockuser.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  15KB  |  721 lines

  1. /* Higher level user subroutines built on top of the socket primitives
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by PA0GRI
  5.  */
  6. #include "global.h"
  7. #include "config.h"
  8. #ifdef    ANSIPROTO
  9. #include <stdarg.h>
  10. #endif
  11. #include "mbuf.h"
  12. #include "proc.h"
  13. #include "socket.h"
  14. #ifdef    LZW
  15. #include "lzw.h"
  16. #endif
  17. #include "usock.h"
  18. #include "session.h"
  19. #include "nr4.h"
  20.  
  21. /*
  22. #define oldusputs
  23. */
  24.  
  25. /* Higher-level receive routine, intended for connection-oriented sockets.
  26.  * Can be used with datagram sockets, although the sender id is lost.
  27.  */
  28. int
  29. recv(s,buf,len,flags)
  30. int s;        /* Socket index */
  31. char *buf;    /* User buffer */
  32. int len;    /* Max length to receive */
  33. int flags;    /* Unused; will eventually select oob data, etc */
  34. {
  35.     struct mbuf *bp;
  36.     int cnt;
  37.  
  38.     if(len == 0)
  39.         return 0;    /* Otherwise would be interp as "all" */
  40.  
  41.     cnt = recv_mbuf(s,&bp,flags,NULLCHAR,(int *)NULL);
  42.     if(cnt > 0){
  43.         cnt = min(cnt,len);
  44.         pullup(&bp,buf,(int16)cnt);
  45.         free_p(bp);
  46.     }
  47.     return cnt;
  48. }
  49. /* Higher level receive routine, intended for datagram sockets. Can also
  50.  * be used for connection-oriented sockets, although from and fromlen are
  51.  * ignored.
  52.  */
  53. int
  54. recvfrom(s,buf,len,flags,from,fromlen)
  55. int s;        /* Socket index */
  56. char *buf;    /* User buffer */
  57. int len;    /* Maximum length */
  58. int flags;    /* Unused; will eventually select oob data, etc */
  59. char *from;    /* Source address, only for datagrams */
  60. int *fromlen;    /* Length of source address */
  61. {
  62.     struct mbuf *bp;
  63.     register int cnt;
  64.  
  65.     cnt = recv_mbuf(s,&bp,flags,from,fromlen);
  66.     if(cnt > 0){
  67.         cnt = min(cnt,len);
  68.         pullup(&bp,buf,(int16)cnt);
  69.         free_p(bp);
  70.     }
  71.     return cnt;
  72. }
  73. /* High level send routine */
  74. int
  75. send(s,buf,len,flags)
  76. int s;        /* Socket index */
  77. char *buf;    /* User buffer */
  78. int len;    /* Length of buffer */
  79. int flags;    /* Unused; will eventually select oob data, etc */
  80. {
  81.     register struct mbuf *bp;
  82.     char sock[MAXSOCKSIZE];
  83.     int i = MAXSOCKSIZE;
  84.  
  85.     if(getpeername(s,sock,&i) == -1)
  86.         return -1;
  87.     bp = qdata(buf,(int16)len);
  88.     return send_mbuf(s,bp,flags,sock,i);
  89. }
  90. /* High level send routine, intended for datagram sockets. Can be used on
  91.  * connection-oriented sockets, but "to" and "tolen" are ignored.
  92.  */
  93. int
  94. sendto(s,buf,len,flags,to,tolen)
  95. int s;        /* Socket index */
  96. char *buf;    /* User buffer */
  97. int len;    /* Length of buffer */
  98. int flags;    /* Unused; will eventually select oob data, etc */
  99. char *to;    /* Destination, only for datagrams */
  100. int tolen;    /* Length of destination */
  101. {
  102.     register struct mbuf *bp;
  103.  
  104.     bp = qdata(buf,(int16)len);
  105.     return send_mbuf(s,bp,flags,to,tolen);
  106. }
  107. /* Receive a newline-terminated line from a socket, returning # chars read.
  108.  * The end-of-line sequence is recognized and translated into a single '\n'.
  109.  */
  110. int
  111. recvline(s,buf,len)
  112. int s;        /* Socket index */
  113. char *buf;    /* User buffer */
  114. unsigned len;    /* Length of buffer */
  115. {
  116.     int c;
  117.     int cnt = 0;
  118.  
  119.     while(len-- > 1){
  120.         if((c = recvchar(s)) == EOF){
  121.             cnt = -1;
  122.             break;
  123.         }
  124.         if(buf != NULLCHAR)
  125.             *buf++ = c;
  126.         cnt++;
  127.         if(uchar(c) == '\n')
  128.             break;
  129.     }
  130.     if(buf != NULLCHAR)
  131.         *buf = '\0';
  132.     return cnt;
  133. }
  134. #if    defined(ANSIPROTO)
  135. /* Do printf on a user socket */
  136. int
  137. usprintf(int s,char *fmt,...)
  138. {
  139.     va_list args;
  140.     int len;
  141.  
  142.     va_start(args,fmt);
  143.     len = usvprintf(s,fmt,args);
  144.     va_end(args);
  145.     return len;
  146. }
  147. /* Printf on standard output socket */
  148. int
  149. tprintf(char *fmt,...)
  150. {
  151.     va_list args;
  152.     int len;
  153.  
  154.     va_start(args,fmt);
  155.     len = usvprintf(Curproc->output,fmt,args);
  156.     va_end(args);
  157.     return len;
  158. }
  159.  
  160. #ifdef UNIX
  161.  
  162. /* Print on Tracesession stdout socket */
  163. int
  164. traceprintf(FILE *fp, char *fmt, ...)
  165. {
  166.     extern struct session *Trace;
  167.     extern int Tracesession;
  168.     int tsock;
  169.     va_list args;
  170.     int len;
  171.  
  172.     va_start(args,fmt);
  173.     if (fp == stdout)
  174.     {
  175.         if (Tracesession)
  176.         tsock = Trace->output;
  177.         else
  178.         tsock = Command->output;
  179.         len = usvprintf(tsock, fmt, args);
  180.     }
  181.     else
  182.         len = vfprintf(fp, fmt, args);
  183.     va_end(args);
  184.     return len;
  185. }
  186.  
  187. /* New style - use session manager switch's status entry point */
  188. int
  189. tcmdprintf(char *fmt, ...)
  190. {
  191.     va_list args;
  192.     char *buf;
  193.     int len;
  194.  
  195.     buf = mallocw(SOBUF);
  196.     va_start(args, fmt);
  197.     if ((len = vsprintf(buf, fmt, args)) >= SOBUF)
  198.     {
  199.     log(-1, "tcmdprintf() buffer overflow");
  200.     where_outta_here(1);
  201.     }
  202.     va_end(args);
  203.     sm_status(0, buf);
  204.     free(buf);
  205.     return len;
  206. }
  207.  
  208. /* Print on Command stdout socket or a file */
  209. int
  210. tfprintf(FILE *fp, char *fmt,...)
  211. {
  212.     va_list args;
  213.     int len;
  214.  
  215.     va_start(args,fmt);
  216.     if (fp == stdout)
  217.         len = usvprintf(Command->output, fmt, args);
  218.     else
  219.         len = vfprintf(fp, fmt, args);
  220.     va_end(args);
  221.     return len;
  222. }
  223.  
  224. #endif
  225.  
  226. /* The guts of printf, uses variable arg version of sprintf */
  227. int
  228. usvprintf(int s,char *fmt, va_list args)
  229. {
  230.     int len,withargs;
  231.     char *buf;
  232.  
  233.     if(strchr(fmt,'%') == NULLCHAR){
  234.         /* Common case optimization: no args, so we don't
  235.          * need vsprintf()
  236.          */
  237.         withargs = 0;
  238.         buf = fmt;
  239.         len = strlen(fmt);
  240.     } else {
  241.         /* Use a default value that is hopefully longer than the
  242.          * biggest output string we'll ever print (!)
  243.          */
  244.         withargs = 1;
  245.         buf = mallocw(SOBUF);
  246. /* Start of mod by N4YYH */
  247.         if((len=vsprintf(buf,fmt,args)) >= SOBUF) {
  248.             /* It's too late to be sorry. He's dead, Jim. */
  249. #ifdef STKTRACE
  250.             stktrace();
  251. #endif
  252.             log(s,"usvprintf() has exceeded the size of it's buffer. Restarting NOS.");
  253.             where_outta_here(1);
  254.         }
  255. /* End of mod by N4YYH */
  256. /*
  257.         len = strlen(buf);
  258. */
  259.     }
  260.     if(usputs(s,buf) == EOF)
  261.         len = -1;
  262.     if(withargs)
  263.         free(buf);
  264.     return len;
  265. }
  266. #else
  267. /*VARARGS*/
  268. /* Printf to standard output socket */
  269. int
  270. tprintf(fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
  271. char *fmt;        /* Message format */
  272. int arg1,arg2,arg3;    /* Arguments */
  273. int arg4,arg5,arg6;
  274. int arg7,arg8,arg9;
  275. int arg10,arg11,arg12;
  276. {
  277.     return usprintf(Curproc->output,fmt,arg1,arg2,arg3,arg4,arg5,arg6,
  278.         arg7,arg8,arg9,arg10,arg11,arg12);
  279. }
  280. /* Printf to socket. Doesn't use ANSI vsprintf */
  281. int
  282. usprintf(s,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
  283. int s;            /* Socket index */
  284. char *fmt;        /* Message format */
  285. int arg1,arg2,arg3;    /* Arguments */
  286. int arg4,arg5,arg6;
  287. int arg7,arg8,arg9;
  288. int arg10,arg11,arg12;
  289. {
  290.     int len,withargs;
  291.     char *buf;
  292.  
  293.     if(strchr(fmt,'%') == NULLCHAR){
  294.         /* No args, so we don't need vsprintf() */
  295.         withargs = 0;
  296.         buf = fmt;
  297.         len = strlen(fmt);
  298.     } else {
  299.         /* Use a default value that is hopefully longer than the
  300.          * biggest output string we'll ever print (!)
  301.          */
  302.         withargs = 1;
  303.         buf = mallocw(SOBUF);
  304. /* Start of mod by N4YYH */
  305.         if((len=sprintf(buf,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,
  306.            arg8,arg9,arg10,arg11,arg12)) >= SOBUF) {
  307.             /* It's too late to be sorry. He's dead, Jim. */
  308.             log(s,"usvprintf() has exceeded the size of it's buffer. Restarting NOS.");
  309.             where_outta_here(1);
  310.         }
  311. /* End of mod by N4YYH */
  312. /*        len = strlen(buf);    */
  313.     }
  314.     if(usputs(s,buf) == EOF)
  315.         len = -1;
  316.  
  317.     if(withargs)
  318.         free(buf);
  319.     return len;
  320. }
  321. #endif
  322. /* Buffered putchar to a socket */
  323. int
  324. usputc(s,c)
  325. int s;
  326. char c;
  327. {
  328.     struct usock *up;
  329.     register struct mbuf *bp;
  330.     char *cp;
  331.     int newline,len;
  332.  
  333.     if((up = itop(s)) == NULLUSOCK){
  334.         errno = EBADF;
  335.         return -1;
  336.     }
  337.     if(c == '\n' && (up->flag & SOCK_ASCII)){
  338.         newline = 1;
  339.         len = strlen(up->eol);
  340.     } else {
  341.         newline = 0;
  342.         len = 1;
  343.     }
  344. #ifndef LZW
  345.     /* Make sure there's room in the current buffer, if any */
  346.     if((bp = up->obuf) != NULLBUF){
  347.         if((bp->cnt >= bp->size - len) && usflush(s) == -1)
  348.             return EOF;
  349.     }
  350. #endif
  351.     if(up->obuf == NULLBUF){
  352.         /* Allocate a buffer of appropriate size */
  353. #ifdef notdef
  354.         /* since I now fragment nr4 packets in send_nr4(),
  355.          * don't worry, be happy :-) - WG7J
  356.          */
  357.         switch(up->type){
  358.         case TYPE_NETROML4:
  359.             up->obuf = ambufw(NR4MAXINFO);
  360.             break;
  361.         default:
  362.             up->obuf = ambufw(BUFSIZ);
  363.             break;
  364.         }
  365. #endif
  366.         up->obuf = ambufw(BUFSIZ);
  367.     }
  368.     /* Note: the buffer must be larger than the end-of-line sequence! */
  369.     bp = up->obuf;
  370.     cp = &bp->data[bp->cnt];
  371.     if(newline){
  372.         /* Translate into appropriate end-of-line sequence */
  373. #ifdef    LZW
  374.         for(cp = up->eol;*cp != '\0';cp++)
  375.             if(up->zout == NULLLZW)
  376.                 bp->data[bp->cnt++] = *cp;
  377.             else
  378.                 lzwencode(s,*cp);
  379. #else
  380.         strncpy(cp,up->eol,len);
  381. #endif
  382.     } else {
  383. #ifdef    LZW
  384.         if(up->zout == NULLLZW)
  385.             bp->data[bp->cnt++] = c;
  386.         else
  387.             lzwencode(s,c);
  388.     }
  389. #else
  390.         *cp = c;
  391.     }
  392.     bp->cnt += len;
  393. #endif
  394.     /* Flush if necessary and leave enough room for a comming eol */
  395.     if((c == up->flush && up->flush != -1) || bp->cnt >= bp->size-9)
  396.         if(usflush(s) == -1)
  397.             return -1;
  398.  
  399.     return (int)uchar(c);
  400. }
  401. /* Put a character to standard output socket */
  402. int
  403. tputc(c)
  404. char c;
  405. {
  406.     return usputc(Curproc->output,c);
  407. }
  408. #ifndef    oldusputs
  409. /* Buffered puts to a socket */
  410. int
  411. usputs(s,buf)
  412. int s;
  413. char *buf;
  414. {
  415.     register struct usock *up;
  416.     register struct mbuf *bp;
  417.     char *cp,*wp;
  418.     int16 len,clen;
  419.     int doflush;
  420.     int eol_len;
  421.     int16 flushpt;
  422.     int ascii;
  423.  
  424.     if((up = itop(s)) == NULLUSOCK){
  425.         errno = EBADF;
  426.         return EOF;
  427.     }
  428. #ifdef    LZW
  429.     if(up->zout != NULLLZW){
  430.         while(*buf != '\0')
  431.             if(usputc(s,*buf++) == EOF)
  432.                 return EOF;
  433.         return 0;
  434.     }
  435. #endif
  436.     ascii = up->flag & SOCK_ASCII;
  437.     if(ascii)
  438.         eol_len = strlen(up->eol);
  439. #ifdef __GNUC__
  440.     else
  441.         eol_len = 0;    /* shut off "uninitialized" warning */
  442. #endif
  443.     doflush = (up->flush != -1) && (strchr(buf,up->flush) != NULLCHAR);
  444.     len = strlen(buf);
  445.  
  446.     while(len != 0){
  447.         if(up->obuf == NULLBUF){
  448.             /* Allocate a buffer of appropriate size */
  449. #ifdef notdef
  450.             /* since I now fragment nr4 packets in send_nr4(),
  451.              * don't worry, be happy :-) - WG7J
  452.              */
  453.             switch(up->type){
  454.             case TYPE_NETROML4:
  455.                 clen = NR4MAXINFO;
  456.                 break;
  457.             default:
  458.                 clen = BUFSIZ;
  459.                 break;
  460.             }
  461. #endif
  462.             clen = BUFSIZ;
  463.             up->obuf = ambufw(clen);
  464.         }
  465.         /* Note: the buffer must be larger than the end-of-line sequence! */
  466.         bp = up->obuf;
  467.         wp = &bp->data[bp->cnt];
  468.         if(ascii && (cp = strchr(buf,'\n')) != NULLCHAR){
  469.             /* Copy up to, but not including, newline */
  470.             clen = cp - buf;
  471.         } else {
  472.             /* Copy whole thing */
  473.             clen = len;
  474.         }
  475.         /* ...but no more than the room available */
  476.         clen = min(clen,bp->size - bp->cnt);
  477.         if(clen != 0){
  478.             memcpy(wp,buf,(size_t)clen);
  479.             wp += clen;
  480.             bp->cnt += clen;
  481.             buf += clen;
  482.             len -= clen;
  483.         }
  484.         /* Set flush threshold to allow for eol, if enabled */
  485.         if(ascii)
  486.             flushpt = bp->size - eol_len;
  487.         else
  488.             flushpt = bp->size;
  489.  
  490.         if(ascii && *buf == '\n' && bp->cnt < flushpt){
  491.             /* Add appropriate end-of-line sequence */
  492.             strncpy(wp,up->eol,(size_t)eol_len);
  493.             wp += eol_len;
  494.             bp->cnt += eol_len;
  495.             buf++;    /* Skip newline in buffer */
  496.             len--;
  497.         }
  498.         if(bp->cnt >= flushpt){
  499.             /* Buffer full, flush and get another */
  500.             if(usflush(s) == -1)
  501.                 return EOF;
  502.         }
  503.     }    
  504.     if(doflush && usflush(s) == -1)
  505.         return EOF;
  506.  
  507.     return 0;
  508. }
  509.  
  510. #else
  511.  
  512. int
  513. usputs(s,x)
  514. int s;
  515. register char *x;
  516. {
  517.     while(*x != '\0')
  518.         if(usputc(s,*x++) == EOF)
  519.             return EOF;
  520.     return 0;
  521. }
  522. #endif
  523.  
  524. /* Put a string to standard output socket */
  525. int
  526. tputs(s)
  527. char *s;
  528. {
  529.     return usputs(Curproc->output,s);
  530. }
  531.  
  532. /* Read a raw character from a socket with stream buffering. */
  533. int
  534. rrecvchar(s)
  535. int s;            /* Socket index */
  536. {
  537.     register struct usock *up;
  538. #ifdef    LZW
  539.     register int c;
  540. #endif
  541.  
  542.     if((up = itop(s)) == NULLUSOCK)
  543.         return EOF;
  544. #ifdef    LZW
  545.     if(up->zin != NULLLZW)
  546.         if((c = lzwdecode(up)) != -1)
  547.             return c;
  548. #endif
  549.     /* Replenish if necessary */
  550.     if(up->ibuf == NULLBUF && recv_mbuf(s,&up->ibuf,0,NULLCHAR,0) <= 0)
  551.         return EOF;
  552.  
  553. #ifdef    LZW
  554.     if(up->zin != NULLLZW)
  555.         if((c = lzwdecode(up)) != -1)
  556.             return c;
  557.         else
  558.             return rrecvchar(s);    /* needs replenish */
  559. #endif
  560.     return PULLCHAR(&up->ibuf);    /* Returns -1 if eof */
  561. }
  562. /* This function recognizes the end-of-line sequence for the stream
  563.  * and translates it into a single '\n'.
  564.  */
  565. int
  566. recvchar(s)
  567. int s;            /* Socket index */
  568. {
  569.     int c;
  570.     register struct usock *up;
  571.  
  572.     if((up = itop(s)) == NULLUSOCK)
  573.         return EOF;
  574.  
  575.     c = rrecvchar(s);
  576.  
  577.     if(c != up->eol[0] || !(up->flag & SOCK_ASCII))
  578.         return c;
  579.  
  580.     /* This is the first char of a eol sequence. If the eol sequence is
  581.      * more than one char long, eat the next character in the input stream.
  582.      */
  583.     if(up->eol[1] != '\0'){
  584.         (void)rrecvchar(s);
  585.     }
  586.     return '\n';
  587. }
  588. /* Flush output on a socket stream */
  589. int
  590. usflush(s)
  591. int s;
  592. {
  593.     register struct usock *up;
  594.     struct mbuf *bp;
  595.  
  596.     if((up = itop(s)) == NULLUSOCK)
  597.         return -1;
  598.  
  599.     if(up->obuf != NULLBUF){
  600. #ifdef    LZW
  601.         if(up->zout != NULLLZW)
  602.             lzwflush(up);
  603. #endif
  604.         bp = up->obuf;
  605.         up->obuf = NULLBUF;
  606.         return send_mbuf(s,bp,0,NULLCHAR,0);
  607.     }
  608.     return 0;
  609. }
  610. /* Flush output socket */
  611. void
  612. tflush()
  613. {
  614.     usflush(Current->output);
  615. }
  616.  
  617. /* Print prompt and read one character */
  618. int
  619. keywait(prompt,flush)
  620. char *prompt;    /* Optional prompt */
  621. int flush;    /* Flush queued input? */
  622. {
  623.     int c;
  624.     int i;
  625.  
  626.     if(flush && socklen(Curproc->input,1) != 0)
  627.         recv_mbuf(Curproc->input,NULLBUFP,0,NULLCHAR,0); /* flush */
  628.     if(prompt == NULLCHAR)
  629.         prompt = "Hit enter to continue"; 
  630.     tprintf(prompt);
  631.     tflush();
  632.     c = recvchar(Curproc->input);
  633.     /* Get rid of the prompt */
  634.     for(i=strlen(prompt);i != 0;i--)
  635.         tputc('\b');
  636.     for(i=strlen(prompt);i != 0;i--)
  637.         tputc(' ');
  638.     for(i=strlen(prompt);i != 0;i--)
  639.         tputc('\b');
  640.     tflush();
  641.     return (int)c;
  642. }
  643.  
  644. /* Set the end-of-line sequence on a socket */
  645. int
  646. seteol(s,seq)
  647. int s;
  648. char *seq;
  649. {
  650.     register struct usock *up;
  651.  
  652.     if((up = itop(s)) == NULLUSOCK)
  653.         return -1;
  654.  
  655.     if(seq != NULLCHAR)
  656.         strncpy(up->eol,seq,sizeof(up->eol));
  657.     else
  658.         *up->eol = '\0';
  659.     return 0;
  660. }
  661. /* Enable/disable eol translation, return previous state */
  662. int
  663. sockmode(s,mode)
  664. int s,mode;
  665. {
  666.     struct usock *up;
  667.     int prev;
  668.  
  669.     if((up = itop(s)) == NULLUSOCK)
  670.         return -1;
  671.     usflush(s);
  672.     prev = up->flag;
  673.     switch(mode){
  674.     case SOCK_BINARY:
  675.     case SOCK_ASCII:
  676.         up->flag = mode;
  677.         break;
  678.     default:
  679.         break;
  680.     }
  681.     return prev;
  682. }
  683. /* Specify the character to trigger automatic output buffer
  684.  * flushing, or -1 to disable it. Return the previous setting.
  685.  */
  686. int
  687. setflush(s,c)
  688. int s;
  689. int c;
  690. {
  691.     register struct usock *up;
  692.     int old;
  693.  
  694.     if((up = itop(s)) == NULLUSOCK)
  695.         return -1;
  696.  
  697.     old = up->flush;
  698.     up->flush = c;
  699.     return old;
  700. }
  701.  
  702. /* Set the block mode on a socket - WG7J.
  703.  * Primarily used on convers.c to prevent backlog of data and
  704.  * usprintf() calls blocking because of it...
  705.  * returns previous mode
  706.  */
  707. int sockblock(int s,int value) {
  708.  
  709.     register struct usock *up;
  710.     int oldval;
  711.  
  712.     if((up = itop(s)) == NULLUSOCK){
  713.         errno = EBADF;
  714.         return -1;
  715.     }
  716.     oldval = up->noblock;
  717.     up->noblock = value;
  718.     return oldval;
  719. }
  720.  
  721.